#ifndef __CTRL_EQUALIZER_H__
#define __CTRL_EQUALIZER_H__

#include <wx/wx.h>
#include <wx/control.h>
#include <vector>
#include "filter.h"
#include <wx/event.h>
#include <string>
#include "MyCommon.h"



// 定义自定义事件类
class MyEventEqualizer : public wxCommandEvent {
public:
    MyEventEqualizer(wxEventType eventType = wxEVT_NULL,int id = 0)
        : wxCommandEvent(eventType, id) {
            m_index = -1;
        }

    // 克隆事件对象
//    [[nodiscard]] // C++17 才支持，意思就是函数返回值不能被忽略，否则编译器发出警告
    virtual wxEvent *Clone() const override {
        return new MyEventEqualizer(*this);
    }
    void SetIndex(int index) {
        m_index = index;
    }
    void SetFrequency(double freq) {
        m_freq = freq;
    }
    void SetGain(double gain) {
        m_gain = gain;
    }
    void SetQFactor(double qfactor) {
        m_qfactor = qfactor;
    }
    void SetType(FilterType type) {
        m_type = type;
    }

    int GetIndex() {
        return m_index;
    }
    double GetFrequency() {
        return m_freq;
    }
    double GetGain() {
        return m_gain;
    }
    double GetQFactor() {
        return m_qfactor;
    }
    FilterType GetType() {
        return m_type;
    }
private:
    int m_index;
    double m_freq;
    double m_gain;
    double m_qfactor;
    FilterType m_type;

};

wxDECLARE_EVENT(myEVT_EQUALIZER, MyEventEqualizer);
wxDECLARE_EVENT(myEVT_EQUALIZER_FREQUENCY, MyEventEqualizer);
wxDECLARE_EVENT(myEVT_EQUALIZER_GAIN, MyEventEqualizer);
wxDECLARE_EVENT(myEVT_EQUALIZER_QFACTOR, MyEventEqualizer);
wxDECLARE_EVENT(myEVT_EQUALIZER_TYPE, MyEventEqualizer);

typedef void (wxEvtHandler::*MyEqualizerEventFunction)(MyEventEqualizer &);
#define MyEqualizerEventHandler(func) \
    wxEVENT_HANDLER_CAST(MyEqualizerEventFunction, func)

#define MY_EVT_EQUALIZER(id, fn) \
    wx__DECLARE_EVT1(myEVT_EQUALIZER, id, MyEqualizerEventHandler(fn))
#define MY_EVT_EQUALIZER_FREQUENCY(id, fn) \
    wx__DECLARE_EVT1(myEVT_EQUALIZER_FREQUENCY, id, MyEqualizerEventHandler(fn))
#define MY_EVT_EQUALIZER_GAIN(id, fn) \
    wx__DECLARE_EVT1(myEVT_EQUALIZER_GAIN, id, MyEqualizerEventHandler(fn))
#define MY_EVT_EQUALIZER_QFACTOR(id, fn) \
    wx__DECLARE_EVT1(myEVT_EQUALIZER_QFACTOR, id, MyEqualizerEventHandler(fn))
#define MY_EVT_EQUALIZER_TYPE(id, fn) \
    wx__DECLARE_EVT1(myEVT_EQUALIZER_TYPE, id, MyEqualizerEventHandler(fn))



#define EQUALIZER_MAX_FILTER 8
#define FREQUENCY_LAB_NUM 11

const wxString FilterTypeName[8]={
    "Error",
    "Lowpass",
    "Hightpass",
    "Bandpass",
    "Peak",
    "Notch",
    "Lowshelf",
    "Highshelf",
};

//参数编辑对话框
class FilterParameterDialog : public wxDialog{
public:
    FilterParameterDialog(wxWindowID id=wxID_ANY,wxWindow *parent = nullptr, const wxString& title=wxT("Param Dialog"),FilterType f_type = Peak,double f_center_frequency = 2000,double f_gain = 0,double f_q_factor = 0.747)
        : wxDialog(parent, id, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE),filter_type(f_type),center_frequency(f_center_frequency),gain(f_gain),q_factor(f_q_factor)
    {
        txt_center_frequency = new wxTextCtrl(this, wxID_ANY, wxT("0"), wxDefaultPosition, wxSize(80, -1), wxTE_PROCESS_ENTER);
        txt_center_frequency->SetWindowStyle(wxALIGN_CENTRE | wxTE_PROCESS_ENTER);
        txt_gain = new wxTextCtrl(this, wxID_ANY, wxT("0"), wxDefaultPosition, wxSize(80, -1), wxTE_PROCESS_ENTER);
        txt_gain->SetWindowStyle(wxALIGN_CENTRE | wxTE_PROCESS_ENTER);
        txt_q_factor = new wxTextCtrl(this, wxID_ANY, wxT("0"), wxDefaultPosition, wxSize(80, -1), wxTE_PROCESS_ENTER);
        txt_q_factor->SetWindowStyle(wxALIGN_CENTRE | wxTE_PROCESS_ENTER);
        listbox_type = new wxComboBox(this, wxID_ANY, wxT("0"), wxDefaultPosition, wxSize(80, -1), 0, nullptr, wxCB_DROPDOWN | wxCB_READONLY);
        lab_center_frequency = new wxStaticText(this, wxID_ANY, wxT("Center Frequency:"));
        lab_center_frequency->SetWindowStyle(wxALIGN_RIGHT);
        lab_gain = new wxStaticText(this, wxID_ANY, wxT("Gain:"));
        lab_gain->SetWindowStyle(wxALIGN_RIGHT);
        lab_q_factor = new wxStaticText(this, wxID_ANY, wxT("Q Factor:"));
        lab_q_factor->SetWindowStyle(wxALIGN_RIGHT);
        lab_type = new wxStaticText(this, wxID_ANY, wxT("Type:"));
        lab_type->SetWindowStyle(wxALIGN_RIGHT);

        btn_ok = new wxButton(this, wxID_ANY, wxT("OK"));
        btn_cancel = new wxButton(this, wxID_ANY, wxT("Cancel"));
        for(int i=1; i<8; i++)
        {
            listbox_type->Append(FilterTypeName[i]);
        }

        layout_center_frequency = new wxBoxSizer(wxHORIZONTAL);
        layout_center_frequency->Add(lab_center_frequency,1,wxEXPAND);
        layout_center_frequency->Add(txt_center_frequency,1,wxEXPAND);
        layout_gain = new wxBoxSizer(wxHORIZONTAL);
        layout_gain->Add(lab_gain,1,wxEXPAND);
        layout_gain->Add(txt_gain,1,wxEXPAND);
        layout_q_factor = new wxBoxSizer(wxHORIZONTAL);
        layout_q_factor->Add(lab_q_factor,1,wxEXPAND);
        layout_q_factor->Add(txt_q_factor,1,wxEXPAND);
        layout_type = new wxBoxSizer(wxHORIZONTAL);
        layout_type->Add(lab_type,1,wxEXPAND);
        layout_type->Add(listbox_type,1,wxEXPAND);
        layout_main = new wxBoxSizer(wxVERTICAL);
        layout_main->Add(layout_center_frequency,0,wxEXPAND);
        layout_main->Add(layout_gain,0,wxEXPAND);
        layout_main->Add(layout_q_factor,0,wxEXPAND);
        layout_main->Add(layout_type,0,wxEXPAND);
        layout_main->Add(btn_ok,0,wxEXPAND);
        layout_main->Add(btn_cancel,0,wxEXPAND);

        this->SetSizer(layout_main);
        // this->SetSize(300, 300);
        // this->SetMinSize(wxSize(300, 300));
        // this->SetMaxSize(wxSize(300, 300));
        Bind(wxEVT_BUTTON, &FilterParameterDialog::OnOK, this, btn_ok->GetId());
        Bind(wxEVT_BUTTON, &FilterParameterDialog::OnCancel, this, btn_cancel->GetId());
        listbox_type->SetSelection((int)filter_type - 1);
        SetFrequency(center_frequency);
        SetGain(gain);
        SetQFactor(q_factor);
        SetType(filter_type);

        Bind(wxEVT_TEXT_ENTER, &FilterParameterDialog::OnTxtCenterFrequency, this, txt_center_frequency->GetId());
        Bind(wxEVT_TEXT_ENTER, &FilterParameterDialog::OnTxtGain, this, txt_gain->GetId());
        Bind(wxEVT_TEXT_ENTER, &FilterParameterDialog::OnTxtQFactor, this, txt_q_factor->GetId());
        Bind(wxEVT_COMBOBOX, &FilterParameterDialog::OnListboxType, this, listbox_type->GetId());
    }
    void SetType(FilterType type) { 
        filter_type = type;
        listbox_type->SetSelection((int)type - 1);
    }
    void SetFrequency(double freq) {
        center_frequency = freq;
        // txt_center_frequency->SetValue(wxString(std::to_string(freq)));
        txt_center_frequency->SetValue(DoubleToString(freq));
    }
    void SetGain(double _gain) {
        gain = _gain;
        txt_gain->SetValue(wxString(DoubleToString(gain)));
    }
    void SetQFactor(double qfactor) {
        q_factor = qfactor;
        txt_q_factor->SetValue(wxString(DoubleToString(q_factor)));
    }
    FilterType GetType() { return filter_type; }
    double GetFrequency() { return center_frequency; }
    double GetGain() { return gain; }
    double GetQFactor() { return q_factor; }

    std::string DoubleToString(double value){
        // std::string str;
        // str = std::to_string(value);
        // size_t dotIndex = str.find('.');
        // if(dotIndex != std::string::npos)
        // {
        //     size_t nonZeroIndex = str.find_last_not_of('0', (unsigned long long)str.length() - 1);
        //     if (nonZeroIndex != std::string::npos) {
        //         str = str.substr(0, nonZeroIndex+1); // 截取字符串，去掉末尾的'0'
        //     }
        //     if(str.at(str.length()-1) == '.')
        //     {
        //         str = str.substr(0, str.length()-1);
        //     }
        // }
        std::string str = mDoubleToString(value);
        return str;
    }
private:
    void OnOK(wxCommandEvent &event){
        // exit(0);
        // close(true);
        EndModal(wxID_OK);
    }
    void OnCancel(wxCommandEvent &event){
        // exit(0);
        // close(true);
        EndModal(wxID_CANCEL);
    }

    void OnTxtCenterFrequency(wxCommandEvent &event){
        double cf;
        wxString str_cf = txt_center_frequency->GetValue();
        bool ret = str_cf.ToDouble(&cf);
        if(ret == true)
        {
            center_frequency = cf;
        }
        SetFrequency(center_frequency);
    }

    void OnTxtGain(wxCommandEvent &event){
        double gain;
        wxString str_gain = txt_gain->GetValue();
        bool ret = str_gain.ToDouble(&gain);
        if(ret == true)
        {
            this->gain = gain;
        }
        SetGain(this->gain);
    }

    void OnTxtQFactor(wxCommandEvent &event){
        double qfactor;
        wxString str_qfactor = txt_q_factor->GetValue();
        bool ret = str_qfactor.ToDouble(&qfactor);
        if(ret == true)
        {
            this->q_factor = qfactor;
        }
        SetQFactor(this->q_factor);
    }

    void OnListboxType(wxCommandEvent &event){
        int index = listbox_type->GetSelection();
        filter_type = (FilterType)(index + 1);
    }

    FilterType filter_type;
    double center_frequency;
    double gain;
    double q_factor;
    wxTextCtrl *txt_center_frequency;
    wxTextCtrl *txt_gain;
    wxTextCtrl *txt_q_factor;
    wxStaticText *lab_center_frequency;
    wxStaticText *lab_gain;
    wxStaticText *lab_q_factor;
    wxStaticText *lab_type;
    // wxListBox *listbox_type;
    // wxChoice *listbox_type;
    wxComboBox *listbox_type;
    wxButton *btn_ok;
    wxButton *btn_cancel;
    wxBoxSizer *layout_main;
    wxBoxSizer *layout_center_frequency;
    wxBoxSizer *layout_gain;
    wxBoxSizer *layout_q_factor;
    wxBoxSizer *layout_type;
    wxBoxSizer *layout_btn;

};

// 自定义按钮控件类
class GraphicEqualizer : public wxControl {
public:
    GraphicEqualizer(wxWindow *parent = nullptr,
                wxWindowID id = wxID_ANY,
                const wxString &label = "",
                const wxPoint &pos = wxDefaultPosition,
                const wxSize &size = wxDefaultSize);
    ~GraphicEqualizer();
    void AddFilter(FilterType type, double frequency, double gain,double qfactor);
    void SetSampleRate(double rate);
    void SetFilterType(int index,FilterType type);
    void SetFilterGain(int index, double gain);
    void SetFilterQFactor(int index, double qfactor);
    void SetFilterFrequency(int index, double frequency);
    double GetSampleRate(int index);
    FilterType GetFilterType(int index);
    double GetFilterGain(int index);
    double GetFilterQFactor(int index);
    double GetFilterFrequency(int index);
    void FilterUpdate(int index);
    void FilterUpdateAll(void);
    void ClearAllFilter(void);

private:
    void OnSize(wxSizeEvent &event);
    void OnPaint(wxPaintEvent &event);
    void OnMouseMove(wxMouseEvent &event);
    void OnMouseDown(wxMouseEvent &event);
    void OnMouseUp(wxMouseEvent &event);
    void OnMouseWheel(wxMouseEvent &event);
    void OnMouseLeftDClick(wxMouseEvent &event);

private:
    typedef struct {
        // double sample_rate;
        double center_frequency;
        double gain;
        double q_factor;
        FilterType type;
        std::vector<double> frequency_response_data;
    }EqualizerData;

    void ComputeCurveCoordX(double start_freq, double end_freq, double freq_step);
    void GetFrequencyResponseData(double start_freq, double end_freq,double freq_step,double sampleRate,FilterCoefficient &coefficient,std::vector<double> &fq_data);
    int GetMouseClickArea(wxMouseEvent &event);

    wxMutex mutex;
    wxString label_title;
    std::vector<EqualizerData *> filter_data_list;
    std::vector<double> coord_coef_x;
    double coord_coef_y;
    double freq_interval;
    double freq_start;
    double freq_end;
    double sample_rate;
    double gain_max;
    double q_factor_max;
    double q_factor_min;
    bool mouse_down;
    bool mouse_first_down;
    double hzLogDiff;
    int current_select_index;
    MyEventEqualizer equalizer_event;

    const int left_margin = 30;
    const int right_margin = 20;
    const int top_margin = 40;
    const int bottom_margin = 30;

    const wxColour curve_color[EQUALIZER_MAX_FILTER] = {
            wxColour(140, 200, 255),
            wxColour(255, 182, 193),
            wxColour(  0, 255, 255),
            wxColour( 32, 178, 170),
            wxColour(255, 228, 196),
            wxColour(138,  43, 226),
            wxColour(255,   0, 255),
            wxColour( 95, 158, 160)
    };
    const double hz_lab[FREQUENCY_LAB_NUM]={
            20,
            50,
            100,
            200,
            500,
            1000,
            2000,
            5000,
            10000,
            16000,
            23000
    };
    const wxString hz_lab_string[FREQUENCY_LAB_NUM]={
            "20",
            "50",
            "100",
            "200",
            "500",
            "1K",
            "2K",
            "5K",
            "10K",
            "16K",
            "23K",
    };
    double hz_lab_axis_coef[FREQUENCY_LAB_NUM];

    wxDECLARE_EVENT_TABLE();
};

#endif
